package com.jagochan.module.rbac.config.satoken;


import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.jagochan.common.result.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Slf4j
@Configuration
public class JagochanSaTokenConfiguration implements WebMvcConfigurer {
    @Value("${jagochan.static-resource-location}")
    private String staticResourceLocation;

    /**
     * 注册 [Sa-Token全局过滤器]
     */
    @Bean
    public SaServletFilter getSaServletFilter() {
        return new SaServletFilter()
                // 指定 拦截路由 与 放行路由  /* addExclude里面为 排除掉 **/
                .addInclude("/**")
                .addExclude("/api/user/login")
                .addExclude("/api/user/captcha")
                .addExclude("/api/user/init-admin")
                .addExclude("/ai/**")

                // 认证函数: 每次请求都会进行拦截
                .setAuth(obj -> {
                    log.debug("--- 进入Sa-Token全局认证 ---");
                    // 输出 API 请求日志，方便调试代码
                    // 登录认证 -- 拦截所有路由，并排除/api/sysUser/login 用于开放登录
                    SaRouter.match("/**", "/api/user/login", StpUtil::checkLogin);
                    // 更多拦截处理方式，请参考“路由拦截式鉴权”章节 */
                })

                // 异常处理函数：每次认证函数发生异常时执行此函数
                .setError(e -> {
                    log.error("--- 进入Sa-Token异常处理 ---");
                    log.error(e.getMessage());

                    if (e instanceof NotLoginException) {
                        // 未授权向前端返回600
                        return SaResult.error(e.getMessage()).setCode(600);
                    }
                    return ResultUtils.error(e.getMessage());
                })

                // 前置函数：在每次认证函数之前执行（BeforeAuth 不受 includeList 与 excludeList 的限制，所有请求都会进入），还有处理跨域请求的
                .setBeforeAuth(r -> {
                    // 如果是预检请求，则立即返回到前端
                    SaRouter.match(SaHttpMethod.OPTIONS)
                            .free(re -> log.debug("--- OPTIONS预检请求，不做处理 ---"))
                            .back();
                });
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/images/**")
                .addResourceLocations(staticResourceLocation);
    }

    // 注册 Sa-Token 拦截器，打开注解式鉴权功能
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        log.debug("注册拦截器了");
        // 注册 Sa-Token 拦截器，打开注解式鉴权功能
        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
    }

    /**
     * 引入密码加密类
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}